
package ru.niir.goodfil.ui;

import java.util.ArrayList;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * Отправка сообщения по электронной почте.
 * @author Носов А.В.
 */
public class Mailer {

    // Variables declaration
    private Session session;
    /**Адрес электронной почты отправителя*/
    private String from;
    /**Тема сообщения*/
    private String subject;
    /**Список получателей*/
    private ArrayList toList = new ArrayList();
    /**Список получателей копии*/
    private ArrayList ccList = new ArrayList();
    /**Список получателей слепой копии*/
    private ArrayList bccList = new ArrayList();
    /**Текст сообщения*/
    private String body;
    /**Хост SMTP*/
    private String mailHost;
    /**Уровень детализации вывода*/
    private boolean verbose;
    /**Сообщение об ошибке*/
    private String errorMsg;
    /**Внешняя авторизация для отправки почты*/
    private boolean autorization = false;
    /**Имя пользователя для авторизации. Необходимо только если нужна внешняя авторизация.*/
    private String userName = "";
    /**Пароль для авторизации. Необходим только если нужна внешняя авторизация.*/
    private String password = "";
    // End of variables declaration

    /**
     * Возвращает адрес электронной почты отправителя.
     * @return адрес электронной почты отправителя
     */
    public String getFrom() {
        return from;
    }

    /**
     * Устанавливает адрес электронной почты отправителя.
     * @param from адрес электронной почты отправителя
     */
    public void setFrom(String from) {
        this.from = from;
    }

    /**
     * Возвращает тему сообщения.
     * @return тема сообщения
     */
    public String getSubject() {
        return subject;
    }

    /**
     * Устанавливает тему сообщения.
     * @param subject тема сообщения
     */
    public void setSubject(String subject) {
        this.subject = subject;
    }

    /**
     * Возвращает список получателей в виде массива строк.
     * @return список получателей в виде массива строк
     */
    public ArrayList getToList() {
        return toList;
    }

    /**
     * Устанавливает список получателей в виде массива строк.
     * @param toList список получателей в виде массива строк
     */
    public void setToList(ArrayList toList) {
        this.toList = toList;
    }

    /**
     * Устанавливает получателей по строке.
     * @param s строка получателей
     */
    public void setToList(String s) {
        this.toList = tokenize(s);
    }

    /**
     * Добавляет в список "To" одного получтеля.
     * @param to получатель
     */
    public void addTo(String to) {
        toList.add(to);
    }

    /**
     * Возвращает список получателей копии в виде массива строк.
     * @return список получателей
     */
    public ArrayList getCcList() {
        return ccList;
    }

    /**
     * Устанавливает получателей копии по объекту ArrayList.
     * @param ccList список получателей копии
     */
    public void setCcList(ArrayList ccList) {
        this.ccList = ccList;
    }

    /**
     * Устанавливает получателей копии по строке.
     * @param s строка получателей копии
     */
    public void setCcList(String s) {
        ccList = tokenize(s);
    }

    /**
     * Добаляет одного получателя копии.
     * @param cc получаель копии
     */
    public void addCc(String cc) {
        ccList.add(cc);
    }

    /**
     * Возващаем список получателей слепой копии в виде массива строк.
     * @return список получателей слепой копии в виде массива строк
     */
    public ArrayList getBccList() {
        return bccList;
    }

    /**
     * Устанавливает список получателей слепой копии в виде массива строк.
     * @param bccList список получателей слепой копии в виде массива строк
     */
    public void setBccList(ArrayList bccList) {
        this.bccList = bccList;
    }

    /**
     * Усанавливает список получателей слепой копии в видем строки.
     * @param s список получателей слепой копии в видем строки
     */
    public void setBccList(String s) {
        bccList = tokenize(s);
    }

    /**
     * Добавляет получателя слепой копии.
     * @param bcc получатель слепой копии.
     */
    public void addBcc(String bcc) {
        bccList.add(bcc);
    }

    /**
     * Возвращает текст сообщения.
     * @return текст сообщения
     */
    public String getBody() {
        return body;
    }

    /**
     * Устанавливает текст сообщения.
     * @param body текст сообщения
     */
    public void setBody(String body) {
        this.body = body;
    }

    /**
     * Установка хоста пересылки SMTP.
     * @param mailHost SMTP
     */
    public void setMailHost(String mailHost) {
        this.mailHost = mailHost;
    }

    /**
     * Возвращает уровень детализации.
     * @return уровень детализации
     */
    public boolean isVerbose() {
        return verbose;
    }

    /**
     * Устанавливает уровень детализации.
     * @param verbose уровень детализации
     */
    public void setVerbose(boolean verbose) {
        this.verbose = verbose;
    }

    /**
     * Внешняя авторизация для отправки почты
     * @param autorization
     */
    public void setAutorization(boolean autorization) {
        this.autorization = autorization;
    }

    /**
     * Устанавливает имя пользователя. Поле необходимо для внешней авторизации
     * на сервере для отправки письма. Настройки самого сервера.
     * @param userName имя пользователя
     */
    public void setUserName(String userName) {
        this.userName = userName.trim();
    }

    /**
     * Устанавливает пароль. Поле необходимо для внешней авторизации
     * на сервере для отправки письма. Настройки самого сервера.
     * @param password пароль
     */
    public void setPassword(String password) {
        this.password = password.trim();
    }

    /**
     * Проверка возможности отправки сообщения.
     * @return true
     */
    private boolean isComplete() {
        if (from == null || from.length()==0) {
            errorMsg = "Не заполнено поле отправителя.";
            return false;
        }
        if (subject==null || subject.length()==0) {
            errorMsg = "Нет темы сообщения.";
            return false;
        }
        if (toList.size()==0) {
            errorMsg = "Нет получателя.";
            return false;
        }
        if (body==null || body.length()==0) {
            errorMsg = "Нет текста сообщения.";
            return false;
        }
        if (mailHost==null || mailHost.length()==0) {
            errorMsg = "Нет хоста SMTP.";
            return false;
        }
        if (autorization)
            if (userName.equals("")) {
                errorMsg = "Поле имя пользователя должно быть заполнено.";
                return false;
        }
        if (autorization)
            if (password.equals("")) {
                errorMsg = "Поле пароль должно быть заполнено.";
                return false;
        }
        return true;
    }

    /**
     * Отправка сообщения. После того как все поля были заполнены.
     * @throws javax.mail.MessagingException
     */
    public synchronized void doSend() throws MessagingException {
        if (!isComplete()) throw new IllegalArgumentException(errorMsg);

        Properties props = new Properties();
        props.put("mail.smtp.host", mailHost);

        // Нужна авторизация для отправки почты
        if (autorization) props.put("mail.smtps.auth", "true");

        if (session == null) {
//            if (autorization) {
//                Store store = session.getStore("pop3s");
//                store.connect(mailHost, userName, password);
//            } else session = Session.getDefaultInstance(props, null);
            session = Session.getDefaultInstance(props, null);
            if (verbose) session.setDebug(true);
        }

        final Message mesg = new MimeMessage(session);

        InternetAddress[] addresses;

        // Список адресов TO
        addresses = new InternetAddress[toList.size()];
        for (int i=0; i<addresses.length; i++)
            addresses[i] = new InternetAddress(String.valueOf(toList.get(i)));
        mesg.setRecipients(Message.RecipientType.TO, addresses);

        // Адрес отправителя.
        mesg.setFrom(new InternetAddress(from));

        //Список адресов получателей копии.
        addresses = new InternetAddress[ccList.size()];
        for (int i=0; i<addresses.length; i++)
            addresses[i] = new InternetAddress(String.valueOf(ccList.get(i)));
        mesg.setRecipients(Message.RecipientType.CC, addresses);

        //Список адресов получателей слепой копии.
        addresses = new InternetAddress[bccList.size()];
        for (int i=0; i<addresses.length; i++)
            addresses[i] = new InternetAddress(String.valueOf(bccList.get(i)));
        mesg.setRecipients(Message.RecipientType.BCC, addresses);

        //Тема сообщения.
        mesg.setSubject(subject);

        //Тело сообщения.
        mesg.setText(body);

        new Thread() {
            @Override
            public void run() {
                try {
                    if (autorization) {
                        Transport transport = session.getTransport("smtps");
                        transport.connect(mailHost, userName, password);
                        transport.sendMessage(mesg, mesg.getAllRecipients());
                        //transport.send(mesg);
                    } else Transport.send(mesg);
                } catch (MessagingException e) {
                    throw  new IllegalArgumentException("Ошибка при передаче: " + e.toString());
                }
            }
        }.start();
    }

    /**
     * Отправка сообщения в одно действие.
     * @param mailHost Хост SMTP
     * @param recipient получатель
     * @param sender отправитель
     * @param subject тема
     * @param message сообщение
     * @throws javax.mail.MessagingException отправка прошла не удачно
     */
    public static void send(String mailHost, String recipient, String sender, String subject, String message) throws MessagingException {
        Mailer m = new Mailer();
        m.setMailHost(mailHost);
        m.addTo(recipient);
        m.setFrom(sender);
        m.setSubject(subject);
        m.setBody(message);
        m.doSend();
    }

    /**
     * Отправка сообщения в одно действие.
     * @param mailHost Хост SMTP
     * @param recipient получатель
     * @param sender отправитель
     * @param subject тема
     * @param message сообщение
     * @throws javax.mail.MessagingException отправка прошла не удачно
     */
    public static void send(String mailHost, String recipient, String sender, String subject, String message,
            boolean autorization, String username, String password) throws MessagingException {
        Mailer m = new Mailer();
        m.setMailHost(mailHost);
        m.addTo(recipient);
        m.setFrom(sender);
        m.setSubject(subject);
        m.setBody(message);
        m.setAutorization(autorization);
        m.setUserName(username);
        m.setPassword(password);
        m.doSend();
    }

    /**
     * Преобразует список адресов в объект ArrayList.
     * Решение работает для просты имен типа:
     * "ivanov@mail.com, ivanov.ivan@mail.com"
     * В случае сложных имен может не работать:
     * "(Ivanov, Ivan) <ivanov@mail.com>"
     * "Ivanov Ivan <ivanov@mail.com>"
     * @param s строка списка адресов
     * @return лист адресов
     */
    protected ArrayList tokenize(String s) {
        ArrayList al = new ArrayList();
        StringTokenizer tf = new StringTokenizer(s, ".");
        // Для каждого слова, найденного в списке.
        while (tf.hasMoreTokens()) {
            //удаляем пробелы и добавляем к списку
            al.add(tf.nextToken().trim());
        }
        return al;
    }
}
